import 'package:flutter/widgets.dart';

typedef ValueBuilder<T> = T Function(BuildContext context);
typedef Disposer<T> = void Function(BuildContext context, T value);

/// [DelegateWidget]的 State 的代理
///
/// 相关的子类
///  * [ValueStateDelegate]
///  * [BuilderStateDelegate]
abstract class StateDelegate {
  BuildContext _context;

  /// The location in the tree where this widget builds.
  ///
  /// See also [State.context].
  BuildContext get context => _context;

  StateSetter _setState;

  /// Notify the framework that the internal state of this object has changed.
  ///
  /// See the discussion on [State.setState] for more information.
  @protected
  StateSetter get setState => _setState;

  /// Called on [State.initState] or after [DelegateWidget] is rebuilt with a
  /// [StateDelegate] of a different [runtimeType].
  @protected
  @mustCallSuper
  void initDelegate() {}

  /// Called whenever [State.didUpdateWidget] is called
  ///
  /// It is guaranteed for [old] to have the same [runtimeType] as `this`.
  @protected
  @mustCallSuper
  void didUpdateDelegate(covariant StateDelegate old) {}

  /// Called when [DelegateWidget] is unmounted or if it is rebuilt with a
  /// [StateDelegate] of a different [runtimeType].
  @protected
  @mustCallSuper
  void dispose() {}
}

/**
 * [DelegateWidget]继承于[StatefulWidget],用于提供便利的方法,代理实现[StatefulWidget]中默认需要实现的方法
 * 在`class _DelegateWidgetState extends State<DelegateWidget>`默认实现了[StatefulWidget]的所有方法
 * 将 [initState],[didUpdateWidget],[dispose],[build]这四个关键的方法通过[StateDelegate]暴露出去
 */

abstract class DelegateWidget extends StatefulWidget {
  /// Initializes [key] for subclasses.
  ///
  /// The argument [delegate] must not be `null`.
  const DelegateWidget({
    Key key,
    this.delegate,
  })  : assert(delegate != null),
        super(key: key);

  /// The current state of [DelegateWidget].
  ///
  /// It should not be `null`.
  @protected
  final StateDelegate delegate;

  /// 用于定义用户展示的界面,当State执行build方法时会调用此方法
  @protected
  Widget build(BuildContext context);

  @override
  StatefulElement createElement() => _DelegateElement(this);

  @override
  _DelegateWidgetState createState() => _DelegateWidgetState();
}

class _DelegateWidgetState extends State<DelegateWidget> {
  @override
  void initState() {
    super.initState();
    _mountDelegate();
    _initDelegate();
  }

  void _initDelegate() {
    assert(() {
      (context as _DelegateElement)._debugIsInitDelegate = true;
      return true;
    }());
    widget.delegate.initDelegate();
    assert(() {
      (context as _DelegateElement)._debugIsInitDelegate = false;
      return true;
    }());
  }

  void _mountDelegate() {
    widget.delegate
      .._context = context
      .._setState = setState;
  }

  void _unmountDelegate(StateDelegate delegate) {
    delegate
      .._context = null
      .._setState = null;
  }

  @override
  void didUpdateWidget(DelegateWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.delegate != oldWidget.delegate) {
      _mountDelegate();
      if (widget.delegate.runtimeType != oldWidget.delegate.runtimeType) {
        oldWidget.delegate.dispose();
        _initDelegate();
      } else {
        widget.delegate.didUpdateDelegate(oldWidget.delegate);
      }
      _unmountDelegate(oldWidget.delegate);
    }
  }

  @override
  Widget build(BuildContext context) => widget.build(context);

  @override
  void dispose() {
    widget.delegate.dispose();
    _unmountDelegate(widget.delegate);
    super.dispose();
  }
}

class _DelegateElement extends StatefulElement {
  _DelegateElement(DelegateWidget widget) : super(widget);

  bool _debugIsInitDelegate = false;

  @override
  DelegateWidget get widget => super.widget as DelegateWidget;

  @override
  InheritedWidget inheritFromElement(Element ancestor, {Object aspect}) {
    assert(() {
      if (_debugIsInitDelegate) {
        final targetType = ancestor.widget.runtimeType;
        // error copied from StatefulElement
        throw FlutterError('''
inheritFromWidgetOfExactType($targetType) or inheritFromElement() was called
before ${widget.delegate.runtimeType}.initDelegate() completed.

When an inherited widget changes, for example if the value of Theme.of()
changes, its dependent widgets are rebuilt. If the dependent widget's reference
to the inherited widget is in a constructor or an initDelegate() method, then
the rebuilt dependent widget will not reflect the changes in the inherited
widget.

Typically references to inherited widgets should occur in widget build()
methods. Alternatively, initialization based on inherited widgets can be placed
in the didChangeDependencies method, which is called after initDelegate and
whenever the dependencies change thereafter.''');
      }
      return true;
    }());
    return super.inheritFromElement(ancestor, aspect: aspect);
  }
}

/// A base class for [StateDelegate] that exposes a [value] of type [T].
///
/// See also:
///
///  * [SingleValueDelegate], which extends [ValueStateDelegate] to store
///    an immutable value.
///  * [BuilderStateDelegate], which extends [ValueStateDelegate] to build
///    [value] from a function and dispose it when the widget is unmounted.
/// StateDelegate基础上扩展,增加了Value选项
abstract class ValueStateDelegate<T> extends StateDelegate {
  /// The member [value] should not be mutated directly.
  T get value;
}

/// Stores an immutable value.
/// 直接获取value
class SingleValueDelegate<T> extends ValueStateDelegate<T> {
  /// Initializes [value] for subclasses.
  SingleValueDelegate(this.value);

  @override
  final T value;
}

/// A [StateDelegate] that creates and dispose a value from functions.
///
/// See also:
///
///  * [ValueStateDelegate], which [BuilderStateDelegate] implements.
/// value 需要build才能创建出来, 其主要作用是为了捕捉 `initialState`和`dispose`方法,对value的值进行`init`和`dispose`操作,
/// 这也是为什么`bloc`通过build方法创建时,如果它所依赖的widget销毁,这个bloc会执行dispose方法,关闭流事件,尽管它在初始化传入的是一个全局单例
class BuilderStateDelegate<T> extends ValueStateDelegate<T> {
  /// The parameter `builder` must not be `null`.
  BuilderStateDelegate(this._builder, {Disposer<T> dispose})
      : assert(_builder != null),
        _dispose = dispose;

  /// Builder和dispose是 bloc作用域的关键方法
  final ValueBuilder<T> _builder;
  final Disposer<T> _dispose;

  T _value;
  @override
  T get value => _value;

  @override
  void initDelegate() {
    super.initDelegate();
    _value = _builder(context);
  }

  @override
  void didUpdateDelegate(BuilderStateDelegate<T> old) {
    super.didUpdateDelegate(old);
    _value = old.value;
  }

  @override
  void dispose() {
    _dispose?.call(context, value);
    super.dispose();
  }
}

/// DelegateWidget的子类,默认实现了一个便利构造函数,通过`ValueStateDelegate对传入的值进行包裹`
abstract class ValueDelegateWidget<T> extends DelegateWidget {
  /// Initializes [key] for subclasses.
  ///
  /// The argument [delegate] must not be `null`.
  ValueDelegateWidget({
    Key key,
    @required ValueStateDelegate<T> delegate,
  }) : super(key: key, delegate: delegate);

  @override
  @protected
  ValueStateDelegate<T> get delegate => super.delegate as ValueStateDelegate<T>;
}
